package de.justphil.tcg.tcgserver.rest.validators;

import javax.ws.rs.core.Response;

import de.justphil.tcg.tcgserver.commons.i18n.Error;
import de.justphil.tcg.tcgserver.commons.domain.Deck;
import de.justphil.tcg.tcgserver.commons.domain.Game;
import de.justphil.tcg.tcgserver.commons.domain.User;
import de.justphil.tcg.tcgserver.commons.domain.Game.State;
import de.justphil.tcg.tcgserver.commons.domain.containers.NewGame;
import de.justphil.tcg.tcgserver.commons.exceptions.TCGException;
import de.justphil.tcg.tcgserver.commons.management.DataManager;
import de.justphil.tcg.tcgserver.commons.util.StringUtil;

public class NewGameValidator {

	public void validatePost(DataManager dataManager, User user, NewGame newGame) throws TCGException {
		if (newGame == null) {
			throw new TCGException(Error.CLIENT_ERROR_BAD_REQUEST, Response.Status.BAD_REQUEST);
		}
		
		if (newGame.getPlayerDeckId() == 0) {
			throw new TCGException(Error.CLIENT_ERROR_DECK_NOT_FOUND, Response.Status.NOT_FOUND);
		}
		
		// Potentially also throws TCGException(Error.CLIENT_ERROR_DECK_NOT_FOUND, Response.Status.NOT_FOUND)
		Deck deck = dataManager.getDeckById(newGame.getPlayerDeckId());
		
		if (deck.getUserId() != user.getId()) {
			throw new TCGException(Error.CLIENT_ERROR_NOT_DECK_OWNER, Response.Status.FORBIDDEN);
		}
	}
	
	public NewGame validateDelete(DataManager dataManager, User user, String otp) throws TCGException {
		validateOtpNullOrEmpty(otp);
		NewGame newGame = getNewGame(dataManager, otp);
		validateOwnership(newGame, user);
		validateGameState(dataManager.getGameById(newGame.getGameId()));
		
		return newGame;
	}
	
	public NewGame validateGet(DataManager dataManager, User user, String otp) throws TCGException {
		validateOtpNullOrEmpty(otp);
		NewGame newGame = getNewGame(dataManager, otp);
		validateOwnership(newGame, user);
		
		return newGame;
	}
	
	public NewGame validatePut(DataManager dataManager, User user, String otp, NewGame nGame) throws TCGException {
		validatePost(dataManager, user, nGame);
		validateOtpNullOrEmpty(otp);
		NewGame newGame = getNewGame(dataManager, otp);
		
		if (alreadyInGame(newGame, user)) {
			throw new TCGException(Error.CLIENT_ERROR_ALREADY_IN_GAME, Response.Status.FORBIDDEN);
		}
		
		if (newGame.getPlayerIds().size() > 1) {
			throw new TCGException(Error.CLIENT_ERROR_ALL_SLOTS_OCCUPIED, Response.Status.FORBIDDEN);
		}
		
		Game game = dataManager.getGameById(newGame.getGameId());
		if (game.getState() != State.WAITING) {
			throw new TCGException(Error.CLIENT_ERROR_ILLEGAL_GAME_STATE, Response.Status.BAD_REQUEST);
		}
		
		return newGame;
	}
	
	/* ######################################################################## */
	/* ######################################################################## */
	/* ######################################################################## */
	
	private boolean alreadyInGame(NewGame newGame, User player) {
		for(Long userId : newGame.getPlayerIds()) {
			if (userId.longValue() == player.getId()) {
				return true;
			}
		}
		
		return false;
	}
	
	private void validateOtpNullOrEmpty(String otp) throws TCGException {
		if (StringUtil.isNullOrEmpty(otp)) {
			throw new TCGException(Error.CLIENT_ERROR_INVALID_OTP, Response.Status.BAD_REQUEST);
		}
	}
	
	private NewGame getNewGame(DataManager dataManager, String otp) throws TCGException {
		// Potentially throws TCGException(Error.CLIENT_ERROR_NEW_GAME_NOT_FOUND, Response.Status.NOT_FOUND)
		return dataManager.getNewGameByOTP(otp);
	}
	
	private void validateOwnership(NewGame newGame, User user) throws TCGException {
		if (newGame.getPlayerIds().get(0).longValue() != user.getId()) {
			throw new TCGException(Error.CLIENT_ERROR_NOT_GAME_OWNER, Response.Status.FORBIDDEN);
		}
	}
	
	private void validateGameState(Game game) throws TCGException {
		if (game.getState() != State.WAITING) {
			throw new TCGException(Error.CLIENT_ERROR_DELETION_REFUSED, Response.Status.FORBIDDEN);
		}
	}
	
}
